﻿
// Этот плагин выполняет переименование переменных если это возможно.
// При возникновении конфликтов регистрирует ошибку, которая указывает на конфликтную переменную.

// Пример ожидаемой структуры параметров (json):
// {"СтароеИмя1": "НовоеИмя1", "СтароеИмя2": "НовоеИмя2"}

Перем Типы;
Перем ТаблицаОшибок;
Перем ТаблицаЗамен;
Перем Директивы;

Перем ПеременныеДляПереименования;
Перем КонфликтыПриПереименовании;
Перем СтруктураЗамен;
Перем ЦелевыеИмена;
Перем МетодСерверный;

Процедура Открыть(Парсер, Параметры) Экспорт
	
	Если Параметры = Неопределено Тогда
		ВызватьИсключение "Не указаны параметры плагина 'ПереименованиеПеременных'";
	КонецЕсли; 
	
	Типы = Парсер.Типы();
	ТаблицаОшибок = Парсер.ТаблицаОшибок();
	ТаблицаЗамен = Парсер.ТаблицаЗамен();
	Директивы = Парсер.Директивы();

	СтруктураЗамен = Параметры;
	
	ЦелевыеИмена = Новый Структура;
	Для Каждого Элемент Из СтруктураЗамен Цикл
		ЦелевыеИмена.Вставить(Элемент.Ключ, Элемент.Значение);
	КонецЦикла; 
	
	ПеременныеДляПереименования = Новый Соответствие;
	КонфликтыПриПереименовании = Новый Соответствие;
	
	Для Каждого Элемент Из СтруктураЗамен Цикл
		ПеременныеДляПереименования.Вставить(Элемент.Ключ, Элемент.Значение);
	КонецЦикла; 
	
КонецПроцедуры // Открыть()

Функция Закрыть() Экспорт
	Возврат Неопределено;
КонецФункции // Закрыть()

Функция Подписки() Экспорт
	Перем Подписки;
	Подписки = Новый Массив;
	Подписки.Добавить("ПосетитьВыражениеИдентификатор");
	Подписки.Добавить("ПосетитьОбъявлениеМетода");
	Подписки.Добавить("ПокинутьОбъявлениеМетода");
	Возврат Подписки;
КонецФункции // Подписки()

#Область РеализацияПодписок

Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт
	МетодСерверный = Ложь;
	
	ДирективыМетода = ОбъявлениеМетода.Сигнатура.Директивы;
	Если ДирективыМетода.Количество() = 0 Тогда
		МетодСерверный = Истина;
	Иначе
		Для Каждого ТекДиректива ИЗ ДирективыМетода Цикл
			Если ТекДиректива.Тип <> Типы.ОбъявлениеДирективы Тогда
				Продолжить;
			КонецЕсли;
			
			Если ТекДиректива.Директива = Директивы.НаСервере
				Или ТекДиректива.Директива = Директивы.НаСервереБезКонтекста
				Или ТекДиректива.Директива = Директивы.НаКлиентеНаСервереБезКонтекста
				Или ТекДиректива.Директива = Директивы.НаКлиентеНаСервере Тогда
				МетодСерверный = Истина;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	ПеременныеДляПереименования = Новый Соответствие;
	КонфликтыПриПереименовании = Новый Соответствие;
		
	СобратьПеременныеДляПереименования(ОбъявлениеМетода.Сигнатура.Параметры);	
	
	СобратьПеременныеДляПереименования(ОбъявлениеМетода.Переменные);
	
	СписокОчистки = Новый Массив;
	
	Для Каждого Элемент Из ПеременныеДляПереименования Цикл
		
		ТекстЗамены = Элемент.Значение;
				
		Объявление = Элемент.Ключ;
		
		Если Объявление.Тип = Типы.ОбъявлениеПараметра
			Или Объявление.Тип = Типы.ОбъявлениеЛокальнойПеременной Тогда
			
			КонфликтноеОбъявление = КонфликтыПриПереименовании[ТекстЗамены];
			
			Если КонфликтноеОбъявление = Неопределено Тогда
				
				ДанныеТокена = Объявление.Конец;
				
				Замена(ТекстЗамены, ДанныеТокена);
				
			Иначе
				
				СписокОчистки.Добавить(Объявление);
				Ошибка(СтрШаблон("Конфликт при переименовании переменной '%1'", Объявление.Имя), КонфликтноеОбъявление.Начало);
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
	Для Каждого Объявление Из СписокОчистки Цикл
		ПеременныеДляПереименования[Объявление] = Неопределено;
	КонецЦикла; 
	
КонецПроцедуры

Процедура СобратьПеременныеДляПереименования(Объявления)
	
	ТекстЗамены = Неопределено;
	
	Для Каждого Объявление Из Объявления Цикл
		Если СтруктураЗамен.Свойство(Объявление.Имя, ТекстЗамены) Тогда
			ПеременныеДляПереименования[Объявление] = ТекстЗамены;
		ИначеЕсли ЦелевыеИмена.Свойство(Объявление.Имя, ТекстЗамены) Тогда
			КонфликтыПриПереименовании[ТекстЗамены] = Объявление;
		КонецЕсли;
	КонецЦикла;	
	
КонецПроцедуры 

Процедура ПосетитьВыражениеИдентификатор(ВыражениеИдентификатор) Экспорт
	
	Объявление = ВыражениеИдентификатор.Голова.Имя;
	
	ТекстЗамены = Неопределено;
	СтруктураЗамен.Свойство(Объявление, ТекстЗамены);
	
	Если ТекстЗамены <> Неопределено Тогда
		
		// Если МетодСерверный И ТекстЗамены<>"ЭтотОбъект" Тогда
		// 	ТекстЗамены=ТекстЗамены+"()";
		// КонецЕсли;

		КонфликтноеОбъявление = КонфликтыПриПереименовании[ТекстЗамены];
		
		Если КонфликтноеОбъявление = Неопределено Тогда
			
			ДанныеТокена = ВыражениеИдентификатор.Начало;
			
			Замена(ТекстЗамены, ДанныеТокена);
			
		Иначе
			
			ПеременныеДляПереименования[Объявление] = Неопределено;
			Ошибка(СтрШаблон("Конфликт при переименовании переменной '%1'", Объявление.Имя), КонфликтноеОбъявление.Начало);
			
		КонецЕсли; 
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ПокинутьОбъявлениеМетода(ОбъявлениеМетода) Экспорт
	
	ПеременныеДляПереименования.Очистить();
	КонфликтыПриПереименовании.Очистить();
	
КонецПроцедуры

#КонецОбласти // РеализацияПодписок

Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь)
	Ошибка = ТаблицаОшибок.Добавить();
	Ошибка.Источник = "ПереименованиеПеременных";
	Ошибка.Текст = Текст;
	Ошибка.ПозицияНачала = Начало.Позиция;
	Ошибка.НомерСтрокиНачала = Начало.НомерСтроки;
	Ошибка.НомерКолонкиНачала = Начало.НомерКолонки;
	Если Конец = Неопределено Или Конец = Начало Тогда
		Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина;
		Ошибка.НомерСтрокиКонца = Начало.НомерСтроки;
		Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина;
	Иначе
		Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина;
		Ошибка.НомерСтрокиКонца = Конец.НомерСтроки;
		Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина;
	КонецЕсли;
	Ошибка.ЕстьЗамена = ЕстьЗамена;
КонецПроцедуры

Процедура Замена(Текст, Начало, Конец = Неопределено)
	НоваяЗамена = ТаблицаЗамен.Добавить();
	НоваяЗамена.Источник = "ПереименованиеПеременных";
	НоваяЗамена.Текст = Текст;
	НоваяЗамена.Позиция = Начало.Позиция;
	Если Конец = Неопределено Тогда
		НоваяЗамена.Длина = Начало.Длина;
	Иначе
		НоваяЗамена.Длина = Конец.Позиция + Конец.Длина - Начало.Позиция;
	КонецЕсли;
КонецПроцедуры
